using System;
using System.Configuration;
using System.Runtime.InteropServices;
using System.Web;
using System.Web.UI;
using System.Web.UI.WebControls;
using System.Web.UI.WebControls.WebParts;
using System.Web.Security;
using System.Xml.Serialization;
using Microsoft.SharePoint;
using Microsoft.SharePoint.WebControls;
using Microsoft.SharePoint.WebPartPages;
using Microsoft.SharePoint.Administration;
using System.Data;
using System.Data.SqlClient;
using System.Security.Principal;
using System.Net.Mail;
using EAT.Common;

namespace EAT.SiteCollectionManager
{
    [Guid("64ce8f31-2d6c-44dd-badc-f92d718946c2")]
    public class SiteCollectionManager : System.Web.UI.WebControls.WebParts.WebPart
    {
        [DllImport("advapi32.dll")]
        static extern bool RevertToSelf();

        SqlManager   SqlM;

        //
        // DebugLabel displays exception information to the end user.
        //
        Label DebugLabel;

        //
        // WPT is the engine behind displaying and sorting the information of the web part.
        //
        WebPartTable WPT;

        //
        // INDEX provides indices for the columns of the WebPartTable.
        //
        enum INDEX
        {
            INTERNALURL = 0,
            EXTERNALURL,
            OWNER,
            DESCRIPTION,
            TITLE,
            REQUESTER,
            STATUS,
            Max
        }
        public struct ColumnName
        {
            public string Display;
            public string Internal;
            ColumnName(string D, string I)
            {
                Display = D;
                Internal = I;
            }
        };

        ColumnName[] ColumnNames;

        public SiteCollectionManager()
        {
            this.ExportMode = WebPartExportMode.All;
        }

        protected override void CreateChildControls()
        {
            this.Controls.Add(
                              DebugLabel
                              );
        }

        //
        // OnLoad
        // Arguments:
        //      e - EventArgs that may contain Postback data
        // Description:
        //      Initialize internal members and respond to Postback.
        //
        protected override void OnLoad(
                                    EventArgs e
                                    )
        {
            string eventArg;
            string[] Params;
            string tag;
            string action;

            ColumnNames = new ColumnName[(int)INDEX.Max];

            ColumnNames[(int)INDEX.INTERNALURL].Display = Resources.urlColumnHeaderText1;
            ColumnNames[(int)INDEX.INTERNALURL].Internal = "internalUrl";
            ColumnNames[(int)INDEX.EXTERNALURL].Display = Resources.urlColumnHeaderText2;
            ColumnNames[(int)INDEX.EXTERNALURL].Internal = "externalUrl";
            ColumnNames[(int)INDEX.DESCRIPTION].Display = Resources.descriptionColumnHeaderText;
            ColumnNames[(int)INDEX.DESCRIPTION].Internal = "Description";
            ColumnNames[(int)INDEX.OWNER].Display = Resources.ownerColumnHeaderText;
            ColumnNames[(int)INDEX.OWNER].Internal = "Owner";
            ColumnNames[(int)INDEX.TITLE].Display = Resources.titleColumnHeaderText;
            ColumnNames[(int)INDEX.TITLE].Internal = "Title";
            ColumnNames[(int)INDEX.REQUESTER].Display = Resources.requesterColumnHeaderText;
            ColumnNames[(int)INDEX.REQUESTER].Internal = "Requester";
            ColumnNames[(int)INDEX.STATUS].Display = Resources.statusColumnHeaderText;
            ColumnNames[(int)INDEX.STATUS].Internal = "Status";
            
            SqlM = new SqlManager();
            DebugLabel = new Label();
            WPT = new WebPartTable("SCM");

            if (Page.IsPostBack)
            {
                eventArg = Page.Request["__EVENTARGUMENT"];

                //
                // If there are arguments in the postback then parse and respond.
                //

                if (eventArg.Length > 0)
                {
                    Params = eventArg.Split(
                                          ",".ToCharArray()
                                          );


                    //
                    // Postback must have at least 2 parameters.  The first is a tag
                    // indicating the intended target of the postback.  The second is 
                    // an action for the application to perform.
                    //
                    if (Params.Length > 1)
                    {
                        tag = Params[0];
                        action = Params[1];

                        if (WPT.GetTag() == tag)
                        {
                            switch (action)
                            {
                                case "sort":
                                    {
                                        if (Params.Length == 4)
                                        {
                                            //
                                            // The column and direction are read from the URL.
                                            //
                                            WPT.SetSortColumn(Params[2]);
                                            WPT.SetSortOrder(Params[3]);
                                        }
                                        break;
                                    }
                                default:
                                    {
                                        break;
                                    }
                            }
                        }
                    }
                }
            }
            else
            {
                base.OnLoad(e);
            }

            //
            // Construct the site DataTable.  ConstructSiteTable reads the 
            // pending sites from SQL and the existent sites from Sharepoint.
            //
            ConstructSiteTable();
        }

        //
        // MarkSiteDeleted
        // Arguments:
        //      Url - string name of the site to delete.
        // Description:
        //      Set the status of the site in SQL to 'deleted'.
        //
        private void MarkSiteDeleted(
                         String Url
                         )
        {
            try
            {
                SqlM.SetEntry(
                         "SiteProvision", 
                         "Status", 
                         "deleted", 
                         "SiteURL", 
                         Url
                         );
            }
            catch (Exception e)
            {
                DebugLabel.Text += e.Message;
            }
        }

        //
        // ConstructSiteTable
        // Arguments - none.
        // Description:
        //      Build the SiteTable.  Key off of the URL.  Add columns for owner, 
        //      description, title, requester, and workflow status.  Query SQL and 
        //      Sharepoint to populate the table.
        //
        protected void ConstructSiteTable()
        {
            DataColumn[] key;
            DataColumn dc;

            key    = new DataColumn[1];

            key[0] = new DataColumn(
                            ColumnNames[(int)INDEX.INTERNALURL].Internal,
                            typeof(String)
                            );

            WPT.GetTable().Columns.Add(key[0]);
            WPT.GetTable().PrimaryKey = key;

            dc = new DataColumn(
                            ColumnNames[(int)INDEX.EXTERNALURL].Internal,
                            typeof(String)
                            );

            WPT.GetTable().Columns.Add(dc);

            dc = new DataColumn(
                         ColumnNames[(int)INDEX.OWNER].Internal, 
                         typeof(String)
                         );

            WPT.GetTable().Columns.Add(dc);
            
            dc = new DataColumn(
                         ColumnNames[(int)INDEX.DESCRIPTION].Internal, 
                         typeof(String)
                         );

            WPT.GetTable().Columns.Add(dc);

            dc = new DataColumn(
                         ColumnNames[(int)INDEX.TITLE].Internal, 
                         typeof(String)
                         );

            WPT.GetTable().Columns.Add(dc);
            
            dc = new DataColumn(
                         ColumnNames[(int)INDEX.REQUESTER].Internal, 
                         typeof(String)
                         );

            WPT.GetTable().Columns.Add(dc);

            dc = new DataColumn(
                         ColumnNames[(int)INDEX.STATUS].Internal, 
                         typeof(String)
                         );

            WPT.GetTable().Columns.Add(dc);
            GetSiteListFromSP(WPT.GetTable());
            GetPendingListFromSql(WPT.GetTable());
        }

        //
        // Render
        // Arguments:
        //      writer - HtmlTextWriter that outputs the controls.
        // Description:
        //      Render draws the webpart.
        //
        protected override void Render(
                                    HtmlTextWriter writer
                                    )
        {
            string internalUrl;
            string externalUrl;
            //string [] AbsUrls = new string [5];
            string Title;
            string Description;
            string Requester;
            string Status;
            string StatusOut;
            string Owner;
            string Filter;
            SPWeb web = SPControl.GetContextWeb(System.Web.HttpContext.Current);
            
            //
            // Output the webpart as a table.  Columns in the table correspond to
            // the columns of SiteTable (accessed as SortedRows).
            //
            writer.Write("<table border=\"0\" width=\"100%\" class=\"ms-authoringcontrols\">");
            writer.Write(@"<tr class=""grid-header"" align=""left"" style=""color:White;background-color:#5D7B9D;font-weight:bold;"">");
            writer.Write(@"<th><a style=""color:White;"">" + WPT.SortLink(ColumnNames[(int)INDEX.INTERNALURL].Internal, ColumnNames[(int)INDEX.INTERNALURL].Display) + "</th>");
            writer.Write(@"<th><a style=""color:White;"">" + WPT.SortLink(ColumnNames[(int)INDEX.EXTERNALURL].Internal, ColumnNames[(int)INDEX.EXTERNALURL].Display) + "</th>");
            writer.Write(@"<th><a style=""color:White;"">" + WPT.SortLink(ColumnNames[(int)INDEX.TITLE].Internal, ColumnNames[(int)INDEX.TITLE].Display) + "</th>");
            writer.Write(@"<th><a style=""color:White;"">" + WPT.SortLink(ColumnNames[(int)INDEX.DESCRIPTION].Internal, ColumnNames[(int)INDEX.DESCRIPTION].Display) + "</th>");
            writer.Write(@"<th><a style=""color:White;"">" + WPT.SortLink(ColumnNames[(int)INDEX.STATUS].Internal, ColumnNames[(int)INDEX.STATUS].Display) + "</th>");
            writer.Write("<th>&nbsp;</th>");
            writer.Write("</tr>");

            Filter = "Owner = '" + web.CurrentUser.LoginName + "' OR Requester = '" + web.CurrentUser.LoginName +"'";

            foreach (DataRow dr in WPT.GetSortedRows(Filter))
            {
                internalUrl = HttpUtility.HtmlEncode(dr[(int)INDEX.INTERNALURL].ToString().Trim());
                externalUrl = HttpUtility.HtmlEncode(dr[(int)INDEX.EXTERNALURL].ToString().Trim());
                Owner = HttpUtility.HtmlEncode(dr[(int)INDEX.OWNER].ToString().Trim());
                Title       = HttpUtility.HtmlEncode(dr[(int)INDEX.TITLE].ToString().Trim());
                Description = HttpUtility.HtmlEncode(dr[(int)INDEX.DESCRIPTION].ToString().Trim());
                Requester   = HttpUtility.HtmlEncode(dr[(int)INDEX.REQUESTER].ToString().Trim());
                Status      = HttpUtility.HtmlEncode(dr[(int)INDEX.STATUS].ToString().Trim().ToLower());

                switch (Status)
                    {
                    case "pending":
                        {
                            StatusOut = Resources.statusPendingText;
                            break;
                        }
                    case "deleted":
                        {
                            StatusOut = Resources.statusDeletedText;
                            break;
                        }
                    case "approved":
                        {
                            StatusOut = Resources.statusApprovedText;
                            break;
                        }
                    default:
                        {
                            StatusOut = Resources.noStatusAvailableText;
                            break;
                        }
                }


                if (Status == null || Status == "" )
                {
                    StatusOut = Resources.noStatusAvailableText;
                    //
                    // Get the title and description from SP.
                    //
                    SPWebApplication spWebApp = SPWebApplication.Lookup(new Uri(web.Url));
                    using (SPSite s = spWebApp.Sites[internalUrl])
                    {
                        if (s != null)
                        {
                            Title = s.RootWeb.Title;
                            Description = s.RootWeb.Description;
                        }
                    }
                }

                writer.Write("<tr>");

                //
                // Don't display a URL link for pending sites.
                //
                if (Status == "pending")
                {
                    writer.Write("<td>" + internalUrl + "</td>");
                    writer.Write("<td>" + externalUrl + "</td>");
                }
                else
                {
                    writer.Write("<td><a href=" + HttpUtility.UrlPathEncode(internalUrl) + ">" + internalUrl + "</a></td>");
                    writer.Write("<td><a href=" + HttpUtility.UrlPathEncode(externalUrl) + ">" + externalUrl + "</a></td>");
                }
                writer.Write("<td>" + Title + "</td>");
                writer.Write("<td>" + Description + "</td>");
                writer.Write("<td>" + StatusOut + "</td>");
                string DeleteLink = @"<td><a href=" + HttpUtility.UrlPathEncode(internalUrl) + "/_layouts/deleteweb.aspx>" + Resources.deleteVerbText + "</a></td>";
                if (Status == "pending")
                {
                    // A future version should implement the delete link for pending requests
                    //writer.Write("<td>" + Resources.deleteVerbText + "</td>");
                    writer.Write("<td>" + "" + "</td>");
                }
                else
                {
                    writer.Write(DeleteLink);
                }
                writer.Write("</tr>");
            }
            foreach (Control c in this.Controls)
            {
                writer.Write("<tr><td colspan=6>");
                writer.Write(c.ID + " ");
                c.RenderControl(writer);
                writer.Write("</td></tr>");
            }
            writer.Write("</table>");
        }

        //
        // GetSiteListFromSP
        // Arguments:
        //      dt - DataTable to which to add sites.
        // Description:
        //      Populates dt with sites from SP.  Details about the site are read
        //      from the provision db in SQL.
        //
        public void GetSiteListFromSP(
                        DataTable dt
                        )
        {
            DataRow          dr;
            bool             bReverted = false;
            WindowsIdentity  wi = null;
            SPWeb            web;
            SPSiteCollection sites;
            SqlDataReader    reader = null;

            try
            {
                wi = WindowsIdentity.GetCurrent();
                RevertToSelf();
                bReverted = true;
                WindowsIdentity.GetCurrent().Impersonate();

                web   = SPControl.GetContextWeb(System.Web.HttpContext.Current);
                sites = web.Site.WebApplication.Sites;

                foreach (SPSite s in sites)
                {
                    dr = dt.NewRow();
                    dr[(int)INDEX.INTERNALURL] = s.Url.ToString();
                    SPWebApplication spWebApp = SPWebApplication.Lookup(new Uri(web.Url));
                    // big assumption here that second alternate URL is our extended zone URL
                    if (spWebApp.AlternateUrls.Count > 1)
                    {
                        dr[(int)INDEX.EXTERNALURL] = spWebApp.AlternateUrls[1].IncomingUrl.ToString() +
                            s.ServerRelativeUrl.ToString();
                    }
                    else
                    {
                        dr[(int)INDEX.EXTERNALURL] = "";
                    }

                    dr[(int)INDEX.OWNER] = s.Owner.LoginName.ToString();

                    reader = SqlM.GetReader("SiteProvision", "SiteUrl", s.ServerRelativeUrl.ToString());

                    if (reader.Read())
                    {
                        dr[(int)INDEX.DESCRIPTION] = reader["SiteDescription"];
                        dr[(int)INDEX.TITLE]       = reader["SiteTitle"];
                        dr[(int)INDEX.REQUESTER]   = reader["Requester"];
                        dr[(int)INDEX.STATUS]      = reader["Status"].ToString();
                    }
                    dt.Rows.Add(dr);
                    reader.Close();
                    s.Dispose();
                }
            }
            catch (Exception e)
            {
                DebugLabel.Text += e.Message;
            }
            finally
            {
                if (reader != null)
                {
                    reader.Close();
                }
                if (bReverted && wi != null)
                {
                    wi.Impersonate();   
                }
            }
        }

        //
        // GetPendingListFromSql
        // Arguments:
        //      dt - the DataTable to populate.
        // Description:
        //      Adds sites to dt that have a status of Pending in the SQL provision
        //      database.
        //
        public void GetPendingListFromSql(
                        DataTable dt
                        )
        {
            SqlDataReader reader = null;

            try
            {
                reader = SqlM.GetReader("SiteProvision", "Status", "Pending");

                while (reader.Read())
                {
                    DataRow dr = dt.NewRow();
                    dr[(int)INDEX.INTERNALURL] = reader["SiteUrl"];
                    dr[(int)INDEX.EXTERNALURL] = " ";
                    dr[(int)INDEX.OWNER] = null;
                    dr[(int)INDEX.DESCRIPTION] = reader["SiteDescription"];
                    dr[(int)INDEX.TITLE] = reader["SiteTitle"];
                    dr[(int)INDEX.REQUESTER] = reader["Requester"];
                    dr[(int)INDEX.STATUS] = reader["Status"].ToString();
                    dt.Rows.Add(dr);
                }
            }
            catch (Exception e)
            {
                DebugLabel.Text += e.Message;
            }
            finally
            {
                if (reader != null)
                {
                    reader.Close();
                }
            }
        }
    }
}
